package com.sxt.netty.server.handler;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sxt.Service.PackageDataService;
import com.sxt.common.Const;
import com.sxt.config.ChannelCache;
import com.sxt.util.SpringUtil;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
//import cn.hutool.extra.spring.SpringUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

//@ChannelHandler.Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
	private static final Logger log = LoggerFactory.getLogger(ServerHandler.class);
	//
	private ChannelCache channelCache = SpringUtil.getBean(ChannelCache.class);
	//
	private static ConcurrentHashMap<ChannelId, Integer> channelIdleTime = new ConcurrentHashMap<ChannelId, Integer>();
	//
	private PackageDataService packageDataService = SpringUtil.getBean(PackageDataService.class);;
	/**
     * 	功能：读取服务器发送过来的信息
     */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		
		try {
			//=============== channelRead() ==================
			ByteBuf buf = (ByteBuf) msg;
			//
			byte[] bytes = new byte[buf.readableBytes()];
			//复制内容到字节数组bytes
			buf.readBytes(bytes);
			//将字节数组bytes转换为16进制字符串
			String receiveStr = HexUtil.encodeHexStr(bytes);
			System.out.println("16进制字符串：" + receiveStr);
			System.out.println("hand字符串：" + StrUtil.sub(receiveStr, 0, 12));
			System.out.println("hand字符串：" + new String(HexUtil.decodeHex(StrUtil.sub(receiveStr, 0, 12))));
			packageDataService.registerHandler(receiveStr);
			
			String uid = "0210361";
			channelCache.addChannel(ctx.channel(), uid );
			ctx.flush();
		} finally {
			//
			ReferenceCountUtil.release(msg);
		}
		
//		String message = (String) msg;
//		
//		String[] msgDatas = StrUtil.split(StrUtil.removePrefix(message, "$"), ",");
//		// 发送号码
//		String uid = msgDatas[2];
//		channelCache.addChannel(ctx.channel(), uid);
	}
	
	/**
	 * channelReadComplete channel 通道 Read 读取 Complete 完成
	 * 	在通道读取完成后会在这个方法里通知，对应可以做刷新操作 ctx.flush()
	 */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    	ctx.flush();
        System.out.println("服务端接收数据完毕..");
        // 第一种方法：写一个空的buf，并刷新写出区域。完成后关闭sock channel连接。
        //ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        // ctx.flush();
        // ctx.flush(); //
        // 第二种方法：在client端关闭channel连接，这样的话，会触发两次channelReadComplete方法。
        // ctx.flush().close().sync(); // 第三种：改成这种写法也可以，但是这中写法，没有第一种方法的好。
    }

    /*
     * channelAction
     *
     * channel 通道 action 活跃的
     *
     * 	当客户端主动链接服务端的链接后，这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
     *
     */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println(ctx.channel().localAddress().toString() + " 通道已激活！");
	}
	/**
     * channelInactive
     *
     * channel 通道 Inactive 不活跃的
     *
     * 	当客户端主动断开服务端的链接后，这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
     */
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		//log.info("====== channelInactive ======");
		channelCache.removeChannel(ctx.channel());
		ctx.close();
		//log.info("====== Channel close ======");
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		// 第一种方法：写一个空的buf，并刷新写出区域。
		ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
		if (evt instanceof IdleStateEvent) {
			//ctx.writeAndFlush(Unpooled.copiedBuffer(new byte[] {}));
			
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

			IdleStateEvent e = (IdleStateEvent) evt;
			if (e.state() == IdleState.READER_IDLE) {
				log.warn("---READER_IDLE---" + dateFormat.format(new Date()));
				ChannelId channelId = ctx.channel().id();
				Integer times = channelIdleTime.get(channelId);
				if (times == null) {
					channelIdleTime.put(channelId, 1);
				} else {
					int num = times.intValue() + 1;
					if (num >= Const.TIME_OUT_NUM) {
						log.error("--- TIME OUT ---");
						channelIdleTime.remove(channelId);
						channelCache.removeChannel(ctx.channel());
						ctx.close();
					} else {
						channelIdleTime.put(channelId, num);
					}
				}
			}
		} else {
			super.userEventTriggered(ctx, evt);
		}
	}
	/**
     * exceptionCaught
     *
     * channel 通道 Exception
     *
     * 	服务端发生异常的操作
     */
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		channelCache.removeChannel(ctx.channel());
		ctx.close();
		log.error("发生异常:{}", cause.getMessage());
	}

	/**
	 * 释放资源
	 * 
	 * @param msg
	 */
//	private void release(Object msg) {
//		try {
//			ReferenceCountUtil.release(msg);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//	}
	
	/**
     * 
     * @author Taowd
     * TODO  此处用来处理收到的数据中含有中文的时  出现乱码的问题
     * 2017年8月31日 下午7:57:28
     * @param buf
     * @return
     */
    @SuppressWarnings("unused")
	private String getMessage(ByteBuf buf) {
        byte[] con = new byte[buf.readableBytes()];
        buf.readBytes(con);
        try {
            return new String(con, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }
}
